package com.mnxc.gxa.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.mnxc.gxa.JWT.JwtUtils;
import com.mnxc.gxa.dto.QueryUserDTO;
import com.mnxc.gxa.dto.Options;
import com.mnxc.gxa.dto.Result;
import com.mnxc.gxa.dto.UserDTO;
import com.mnxc.gxa.entity.Dept;
import com.mnxc.gxa.entity.Menu;
import com.mnxc.gxa.entity.User;
import com.mnxc.gxa.mapper.DeptMapper;
import com.mnxc.gxa.mapper.UserMapper;
import com.mnxc.gxa.service.IUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mnxc.gxa.utils.PasswordEncoder;
import com.mnxc.gxa.utils.UserHolder;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import static com.mnxc.gxa.utils.SystemConstants.USER_NICK_NAME_PREFIX;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author mnxc
 * @since 2023-06-29
 */
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
    @Resource
    UserMapper userMapper;
    @Resource
    DeptMapper deptMapper;

    @Override
    public Result getAll() {
        // 1.获取数据
        List<User> users = userMapper.getAll();
        // 2.返回
        return Result.ok(users, (long) users.size());
    }

    @Override
    public Result getByPageAndCondition(Integer page, Integer pageSize, QueryUserDTO query) {
        //1.构造分页器
        IPage<User> pageInfo = new Page<>(page,pageSize);
        //2.条件查询
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
        lqw.like(query.getUsername()!=null,User::getUsername,query.getUsername())
                .like(query.getNickname()!=null,User::getUsername,query.getNickname())
                .eq(query.getStatus()!=null,User::getStatus,query.getStatus())
                .eq(query.getDept()!=null,User::getDeptId,query.getDept());
        //查询基本信息
        this.page(pageInfo,lqw);
        //获取Plus信息
        IPage<UserDTO> pageInfoDTO = new Page<>();
        //拷贝分页信息，除数据体
        BeanUtil.copyProperties(pageInfo,pageInfoDTO,"records");
        List<User> records = pageInfo.getRecords();
        List<UserDTO> dtoList = records.stream().map(item -> {
            UserDTO userDTO = BeanUtil.copyProperties(item, UserDTO.class);
            Integer deptId = item.getDeptId();
            Dept dept = deptMapper.selectById(deptId);
            userDTO.setDeptName(dept.getTitle());
            return userDTO;
        }).collect(Collectors.toList());
        pageInfoDTO.setRecords(dtoList);
        return Result.ok(pageInfoDTO);
    }

    @Override
    public Result saveUser(User user) {
        // 0.用户密码加密
        String encode = PasswordEncoder.encode(user.getPassword());
        log.info("encode password = ",encode);
        user.setPassword(encode);
        // 1.保存用户信息
        boolean isSuccess = save(user);
        if(!isSuccess){
            // 2.保存失败，返回报错信息
            return Result.fail("添加用户失败！");
        }
        // 3.保存成功
        return Result.ok();
    }

    @Override
    public Result updateUser(User user) {
        boolean isSuccess = updateById(user);
        if (!isSuccess) {
            return Result.fail("更新用户信息失败！");
        }
        return Result.ok("更新用户信息成功！");
    }

    @Override
    public Result freezeUser(User user) {
        boolean isSuccess = userMapper.freezeUser(user);
        if (!isSuccess) {
            Result.fail("冻结用户失败！");
        }
        return Result.ok("冻结用户成功！");
    }

    @Override
    public Result activeUser(User user) {
        boolean isSuccess = userMapper.activeUser(user);
        if (!isSuccess) {
            Result.fail("激活用户失败！");
        }
        return Result.ok("激活用户成功！");
    }

    @Override
    public Result deleteUser(User user) {
        boolean isSuccess = userMapper.deleteUser(user);
        if (!isSuccess) {
            Result.fail("删除用户失败！");
        }
        return Result.ok("删除用户成功！");
    }

    @Override
    public Result login( User user, HttpSession session) {
        // 0.查询用户
        LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
        lqw.eq(user.getUsername()!=null,User::getUsername,user.getUsername());
        User one = userMapper.selectOne(lqw);
        // 1.判断用户是否存在
        if (one == null) {
            // 2.用户不存在，报错
            return Result.fail("用户不存在！");
        }
        // 3.校验密码
        Boolean isMatches = PasswordEncoder.matches(one.getPassword(), user.getPassword());

        if (!isMatches) {
            // 3.1.密码校验错误，报错
            return Result.fail("用户名或密码错误！");
        }
        // 4.用户名，密码校验成功，用户存入session,UserHolder
        UserDTO userDTO = BeanUtil.copyProperties(one, UserDTO.class);
        // 4.1.创建jwtToken字符串
        String jwtToken = JwtUtils.createJwt(one.getId().toString(), "com.exp.demo", JwtUtils.generalSubject(userDTO), 60 * 60 * 5);


        session.setAttribute("user",userDTO);
        UserHolder.saveUser(userDTO);
        // 5.返回登录成功信息
        return Result.ok(userDTO,jwtToken);
    }

    @Override
    public Result register(User user) {
        // 1.用户名，密码是否为空
        if (StrUtil.isBlank(user.getUsername()) || StrUtil.isBlank(user.getPassword())) {
            // 2.为空报错
            return Result.fail("用户参数错误");
        }
        // 2.判断用户名是否存在
        User one = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUsername, user.getUsername()));

        if (one != null) {
            // 2.1.存在，报错，用户名已存在
            return Result.fail("用户已存在！");
        }
        // 3.密码加密
        String encode = PasswordEncoder.encode(user.getPassword());
        user.setPassword(encode);
        // 4.设置默认参数
        // 4.1.用户头像 TODO
        user.setPicture("default_picture.jpg");
        // 4.2.用户昵称，随机昵称
        String nickname = RandomUtil.randomString(USER_NICK_NAME_PREFIX, 20);
        user.setNickname(nickname);

        // 5.保存用户
        boolean isSave = save(user);
        if (!isSave) {
            return Result.fail("添加用户失败");
        }
        //6.返回
        return Result.ok("注册成功！");
    }

    @Override
    public Result getMenusById(Long id) {
        // 1.获取用户菜单信息
        List<Menu> menuList = userMapper.getMenusById(id);
        // 2.封装成树结构
        List<Options<Menu>> menuOptions = getMenuOptions(menuList);
        log.info("menuOptions = " + menuOptions);
        return Result.ok(menuOptions);
    }

    @Override
    public Result getUserById(Integer id) {
        // 1.获取用户
        User user = userMapper.selectById(id);
        if(user ==null)return Result.fail("用户不存在");
        // 2.返回数据
        UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class);
        return Result.ok(userDTO);
    }

    @Override
    public Result resetPasswordByIds(List<Long> ids) {
        List<User> users = userMapper.selectBatchIds(ids);
        if(users.size() != ids.size()){return Result.fail("用户id不正确"); }
        userMapper.resetPasswordByIds(ids);

        return Result.ok("重置密码成功！");
    }

    public List<Options<Menu>> getMenuOptions(List<Menu> menuList){
        List<Options<Menu>> menuOptions = new ArrayList<>();
        List<Options<Menu>> notFindFather = new ArrayList<>();
        menuList.forEach(item->{
            Options<Menu> option = new Options<>();
            option.setData(item);
            option.setChildren(new ArrayList<>());
            if (item.getPid() == 0){
                menuOptions.add(option);
            } else {
                boolean isFindFather = findFather(menuOptions, option);
                if(!isFindFather)notFindFather.add(option);
            }
        });
        // 1.没有找到父亲的再找
        notFindFather.forEach(item->{
            findFather(menuOptions,item);
        });
        return menuOptions;
    }

    private boolean findFather(List<Options<Menu>> menuOptions, Options<Menu> option) {

        for (Options<Menu> opt : menuOptions) {
            if (opt.getData().getId() == option.getData().getPid()) {
                opt.getChildren().add(option);
                return true;
            } else {
                boolean flag = findFather(opt.getChildren(), option);
                if(flag) return true;
            }
        }
        return false;
    }

}
